package cn.edu.lcu.cs.javaprogramming.thread.producer_consumer.piped;

import lombok.Cleanup;
import lombok.Getter;
import lombok.Setter;
import lombok.SneakyThrows;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.PipedOutputStream;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 生产者线程
 *
 * @author ling
 * @date 2022/5/30 22:28
 */
public class Producer implements Runnable {
    /**
     * 带原子操作的、可自动更新的Long类型，用于生成ID序列。
     */
    private final AtomicLong idSequence = new AtomicLong();
    /**
     * 管道输出流，用于输出生产出来的数据。
     */
    @Getter
    @Setter
    private PipedOutputStream sink;

    public Producer() {
        sink = new PipedOutputStream();
    }


    @SneakyThrows
    @Override
    public void run() {
        // 创建对象输出流，并与管道输出流绑定。
        @Cleanup
        ObjectOutputStream outputStream = new ObjectOutputStream(sink);
        while (true) {
            try {
                // 生产数据
                Product product = produce();
                // 将生产的对象序列化，并输出到对象输出流，即管道输出流
                outputStream.writeObject(product);
                // 随机休眠
                Thread.sleep(new Random().nextInt(2000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 生产产品
     *
     * @return
     */
    private Product produce() {
        Product product = Product.builder()
                // ID序列递增并返回，原子操作，防止修改值时被其它线程抢占。
                .id(idSequence.incrementAndGet())
                .productName("product-" + UUID.randomUUID().toString())
                .unitPrice(new Random().nextInt(1000))
                .build();
        System.out.println(Thread.currentThread().getName() + " 生产了产品 " + product);
        return product;
    }
}
